package com.stdz.counter.core.thread;

import com.stdz.counter.core.constant.ClearLoopType;
import com.stdz.counter.core.constant.ClearMode;
import com.stdz.counter.core.constant.DataMode;
import com.stdz.counter.core.constant.MeterModel;
import com.stdz.counter.core.pool.ClientPool;
import com.stdz.counter.dao.MeterInfoDao;
import com.stdz.counter.dao.MeterRecordDao;
import com.stdz.counter.entity.MeterInfo;
import com.stdz.counter.entity.MeterRecord;
import com.stdz.counter.utils.MeterHelper;
import com.stdz.counter.utils.ModbusHelper;
import com.stdz.counter.utils.ResourceUtil;
import de.re.easymodbus.modbusclient.ModbusClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 *
 */
public class ClearDataThread implements Runnable {

    private static transient Logger logger = LoggerFactory.getLogger(ClearDataThread.class);

    @Resource
    private MeterInfoDao meterInfoDao;
    @Resource
    private MeterRecordDao meterRecordDao;

    private String comPort;

    private List<MeterInfo> meterInfos;

    public ClearDataThread(String comPort, List<MeterInfo> meterInfos) {
        ResourceUtil.autowired(this);
        this.comPort = comPort;
        this.meterInfos = meterInfos;
    }

    @Override
    public void run() {
        logger.info("config refresh thread run start");
        if (this.meterInfos == null || meterInfos.size() == 0) {
            return;
        }
        ModbusClient modbusClient = ClientPool.getInstance().createModbusClient(comPort);
        if (modbusClient == null) {
            return;
        }
        if (modbusClient.isConnected()) {
            logger.info("modbus connect success");
        }
        try {
            this.clear(modbusClient);
        } catch (Throwable t) {
            logger.error("sync data exception:", t);
        } finally {
            ClientPool.getInstance().releaseModbusClient(comPort, modbusClient);
        }
        logger.info("config refresh thread run end");
    }

    private void clear(ModbusClient modbusClient) {
        long currentTimeMillis = System.currentTimeMillis();
        for (MeterInfo meterInfo : meterInfos) {
            try {
                if (!MeterHelper.ifClearEnable(meterInfo, currentTimeMillis)) {
                    if (meterInfo.getClearLoopType() == ClearLoopType.LOOP_OPERTE.getLoopType()
                            && MeterHelper.ifClearOverTime(meterInfo, currentTimeMillis)) {
                        meterInfo.clearOver();
                        meterInfoDao.updateClearOver(meterInfo);
                    }
                } else {
                    this.clearMeterData(modbusClient, meterInfo);
                }
            } catch (Throwable t) {
                logger.error("syncMeterInfo exception:", t);
            }
        }
    }

    private void clearMeterData(ModbusClient modbusClient, MeterInfo meterInfo) {
        if (meterInfo.getClearMode() == ClearMode.SINGLE_CLEAR.getMode()) {
            modbusClient.setUnitIdentifier(meterInfo.getModbusDeviceId());
            ModbusHelper.singleClear1(modbusClient);
            this.syncSuccessToDB(meterInfo);
            this.syncMeterInfo(modbusClient, meterInfo);
        } else if (meterInfo.getClearMode() == ClearMode.BOTH_CLEAR.getMode()) {
            modbusClient.setUnitIdentifier(meterInfo.getModbusDeviceId());
            ModbusHelper.bothClear(modbusClient);
            this.syncSuccessToDB(meterInfo);
            this.syncMeterInfo(modbusClient, meterInfo);
        }

    }

    private void syncSuccessToDB(MeterInfo meterInfo) {
        meterInfo.clearSuccess();
        try {
            int update = meterInfoDao.updateClearSuccess(meterInfo);
            if (update == 0) {
                logger.error("sync clear success to db:{} data to db fail", new Object[]{meterInfo.getMeterId()});
            }
        } catch (Throwable t) {
            logger.error("sync clear success to db exception", t);
        }
    }

    private void syncMeterInfo(ModbusClient modbusClient, MeterInfo meterInfo) {
        MeterModel meterModel = MeterModel.getMeterModel(meterInfo.getMeterModel());
        if (meterModel == null) {
            logger.error("not config meter info right model");
            return;
        }
        DataMode dataMode = DataMode.getDataMode(meterInfo.getDataMode());
        if (dataMode == null) {
            return;
        }
        modbusClient.setUnitIdentifier(meterInfo.getModbusDeviceId());
        int upperRowVal = 0;
        int lowerRowVal = 0;
        int decimalDigit = 0;
        int alarm1 = -1;
        int alarm2 = -1;
        int scaleRate = 0;
        int upperRowPos= meterModel.getDataPos(dataMode.getMode());
        if (upperRowPos > 0) {
            upperRowVal = ModbusHelper.readUpperRowData(modbusClient, meterModel, meterInfo);
            lowerRowVal = ModbusHelper.readLowerRowData(modbusClient, meterModel, meterInfo);
            logger.info("com:{} meterDevice:{}, up:{}, low:{}",
                    new Object[]{comPort, meterInfo.getModbusDeviceId(), upperRowVal, lowerRowVal});
        }
        int decimalDigitPos = meterModel.getDecimalDigitPos();
        if (decimalDigitPos > 0) {
            int[] deimalDigitDatas = ModbusHelper.readData(modbusClient, decimalDigitPos, 1);
            if (deimalDigitDatas.length > 0) {
                logger.info("deimalDigitDatas:{},{}", new Object[]{deimalDigitDatas[0], 1});
            }
            if (deimalDigitDatas != null && deimalDigitDatas.length > 0) {
                decimalDigit = deimalDigitDatas[0] & 0xf;
            }

        }
        int alarm1Pos = meterModel.getAlarm1Pos();
        if (alarm1Pos > 0) {
            alarm1 = ModbusHelper.readAlarm1(modbusClient, meterModel);
        }
        int alarm2Pos = meterModel.getAlarm2Pos();
        if (alarm2Pos > 0) {
            alarm2 = ModbusHelper.readAlarm2(modbusClient, meterModel);
        }
        int scaleRatePos = meterModel.getScalePos();
        if (scaleRatePos > 0) {
            scaleRate = ModbusHelper.readScaleRate(modbusClient, meterModel);
            if (meterModel == MeterModel.CR76 && scaleRate > 0) {
                scaleRate = scaleRate / 10000;
            } else if (meterModel == MeterModel.ST76 && scaleRate > 0) {
                // 实际倍数需要除以100000（10w）,此处不做处理，界面上再处理
            }
        }
        logger.info("com:{} meterDevice:{}, up:{}, low:{}, decimalDigit:{}, scale:{}, al1:{}, al2:{}",
                new Object[]{comPort, meterInfo.getModbusDeviceId(), upperRowVal,
                        lowerRowVal, decimalDigit, scaleRate, alarm1, alarm2});
        int online = 0;
        if (upperRowVal > 0 || lowerRowVal > 0 || scaleRate > 0
                || alarm1 > 0 || alarm2 > 0 || decimalDigit > 0) {
            online = 1;
        }
        meterInfo.setAlarm1(String.valueOf(alarm1));
        meterInfo.setAlarm2(String.valueOf(alarm2));
        meterInfo.setScaleRate(scaleRate);
        meterInfo.setDecimalDigit(decimalDigit);
        meterInfo.setUpperRowVal(upperRowVal);
        meterInfo.setLowerRowVal(lowerRowVal);
        meterInfo.setOnline(online);
        this.syncDB(meterInfo);
    }

    private void syncDB(MeterInfo meterInfo) {
        try {
            int update = meterInfoDao.syncMeterData(meterInfo);
            if (update == 0) {
                logger.error("sync meter:{} data to db fail", new Object[]{meterInfo.getMeterId()});
            }
        } catch (Throwable t) {
            logger.error("sync meter data to db exception", t);
        }
        this.recordLog(meterInfo);
    }

    private void recordLog(MeterInfo meterInfo) {
        MeterRecord meterRecord = new MeterRecord();
        meterRecord.setCreateTime(new Date());
        meterRecord.setName(meterInfo.getMeterName());
        meterRecord.setMeterId(meterInfo.getMeterId());
        meterRecord.setUpperRow(meterInfo.getDisplayUpperRowVal());
        try {
            meterRecordDao.addMeterRecord(meterRecord);
        } catch (Throwable t) {
            logger.error("inject meter record exception:", t);
        }

    }

}
